home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / grafik / bildanzeiger / seepix / source.lha / SeePix.c < prev    next >
C/C++ Source or Header  |  1992-11-27  |  19KB  |  718 lines

  1. /**SeePix.c**************************************************************
  2.  *                                    *
  3.  *   SeePix -- by Hank Schafer                        *
  4.  *                                    *
  5.  *   SeePix is an IFF Picture Viewer.  It works with Lo-Res,        *
  6.  *   Med-Res, Hi-Res, HAM, and EHB formats.  I'm working on support     *
  7.  *   for X-Specs, and Anim5 formats.                    *
  8.  *                                    *
  9.  *   SeePix is based on a program by Olaf Barthel, called        *
  10.  *   'LoadImage'.  As released, LoadImage had a couple of bugs.     *
  11.  *   The Amiga-Key alternatives to menu use didn't all work.  That's    *
  12.  *   been fixed.  There were two separate print functions in LoadImage    *
  13.  *   which behaved exactly the same.  The redundancy was eliminated.    *
  14.  *   LoadImage used the Topaz ROMFONT, and made no allowances for a    *
  15.  *   different system default font (under 2.04).  I added a built-in    *
  16.  *   font.  I've reworked the code considerably from the original       *
  17.  *   release, to allow for optimizations based on time and space.    *
  18.  *                                    *
  19.  *   SeePix features a palette tool which allows "tweaking" of colors    *
  20.  *   prior to printing, allowing you to modify the color printout to    *
  21.  *   more closely resemble the original graphics (Blue is Blue, not    *
  22.  *   Purple).  SeePix can be Iconified.  SeePix features an ARP     *
  23.  *   interface.  SeePix now uses the PathMaster File Selector.        *
  24.  *                                    *
  25.  ************************************************************************
  26.  *                                                                      *
  27.  *   SeePix Copyright © 1992 by Hank Schafer; all rights reserved.      *
  28.  *                                                                      *
  29.  *   This program is free software; you can redistribute it and/or      *
  30.  *   modify it under the terms of the GNU General Public License as     *
  31.  *   published by the Free Software Foundation, either version 1, or    *
  32.  *   (at your option) any later version.                                *
  33.  *                                                                      *
  34.  *   This program is distributed in the hope that it will be useful,    *
  35.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of     *
  36.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  *
  37.  *   General Public License for more details.                           *
  38.  *                                                                      *
  39.  *   You should have received a copy of the GNU General Public License  *
  40.  *   along with this program; if not, write to:                         *
  41.  *                 Free Software Foundation, Inc.                       *
  42.  *                 675 Massachusetts Ave.                               *
  43.  *                 Cambridge  MA  02139, USA                            *
  44.  *                                                                      *
  45.  **************** Special Function Copyright Notices ********************
  46.  *                                    *
  47.  ****LoadImage Copyright Notice:                    *
  48.  *                                    *
  49.  *   LoadImage is © Copyright 1988, 1989, 1990 by MXM, all rights    *
  50.  *   reserved, written by Olaf Barthel.  No guarantees of any kind are    *
  51.  *   made that this program is 100% reliable.  Use this program on    *
  52.  *   your own risk!                            *
  53.  *                                    *
  54.  ****Iconify Copyright Notice:                        *
  55.  *                                    *
  56.  *   Copyright 1987 by Leo L. Schwab.                    *
  57.  *   Permission is hereby granted for use in any and all programs,    *
  58.  *   both Public Domain and commercial in nature, provided this     *
  59.  *   Copyright notice is left intact.                    *
  60.  *                                    *
  61.  ****ColorWindow (Palette) Copyright Notice:                *
  62.  *                                    *
  63.  * ColorWindow Routine    --  Color Window Routines            *
  64.  *     from Book 1 of the Amiga Programmers' Suite by RJ Mical          *
  65.  *                                    *
  66.  * Copyright (C) 1986, 1987, Robert J. Mical                *
  67.  * All Rights Reserved.                         *
  68.  *                                    *
  69.  ****PathMaster Copyright Notice:                    *
  70.  *                                    *
  71.  * -------------------------------------------------------------------- *
  72.  *   Copyright © 1989 Justin V. McCormick.  All Rights Reserved.    *
  73.  * -------------------------------------------------------------------- *
  74.  *                                    *
  75.  *    The PathMaster name is a trademark of Justin V. McCormick.    *
  76.  *                                    *
  77.  *   PathMaster File Selector source and documentation written by:    *
  78.  *                                    *
  79.  *             Justin V. McCormick.                *
  80.  *           Copyright © 1989 by Justin V. McCormick.         *
  81.  *             All Rights Reserved.                *
  82.  *                                    *
  83.  * -------------------------------------------------------------------- *
  84.  ************************************************************************
  85.  *                                    *
  86.  *   Hope this is something you can use and enjoy.            *
  87.  *                                    *
  88.  ************************************************************************/
  89.  
  90. /*
  91.  * SeePix()
  92.  *
  93.  * Will load and display an image file.
  94.  */
  95.  
  96. /* All the external stuff */
  97.  
  98. extern struct Screen *Screen;
  99. extern struct Window *Window;
  100.  
  101. extern struct BitMap ScreenMap;
  102. extern struct BitMap TinyBitMap;
  103. extern struct NewScreen NewScreen;
  104.  
  105. BitMapHeader    InfoHeader;
  106.  
  107. CRange        CycleRange[6];
  108.  
  109. #ifdef    FANCYMENU
  110.  
  111. extern UWORD    PrefColors[];
  112. extern struct Preferences StandardPrefs;
  113.  
  114. #endif                /* FANCYMENU */
  115.  
  116. extern struct MenuItem MenuItem[13];
  117. extern struct Menu Menu;
  118. extern struct Border ReqBrd[];
  119. extern struct Gadget ReqGad;
  120. extern struct Requester Req;
  121. extern struct IntuiText ReqIntTxt[];
  122. extern struct NewWindow NewWindow;
  123.  
  124. extern struct IntuitionBase *IntuitionBase;
  125. extern struct GfxBase *GfxBase;
  126. extern struct ExecBase *SysBase;
  127.  
  128. LONG        ViewModes;
  129.  
  130. /*
  131.  * Get down to bizness...
  132.  */
  133.  
  134. LONG
  135. SeePix(char *FileName, UBYTE ForceScroll, UBYTE ForceLace, UBYTE CycleOnStartup, UBYTE LastOne)
  136. {
  137.     WORD        MaxOffsetX, MaxOffsetY;    /* Some scrolling stuff. */
  138.     volatile WORD   StartOffsetX, StartOffsetY;
  139.  
  140.     WORD        Width, Height;    /* Size of the ViewPort */
  141.  
  142.     WORD        JumpY = 1, JumpX = 1;    /* Scrolljump steps */
  143.  
  144.     UBYTE        WeAreScrolling = FALSE;
  145.     UBYTE        RemakeTheView;
  146.  
  147.     UWORD        MenuNum;
  148.     struct MenuItem *Item;
  149.  
  150.     UBYTE        IsMouse;    /* Scrollmode. */
  151.  
  152.     UBYTE        ChangedColors = FALSE;
  153.  
  154.     UBYTE        IsTiny = FALSE;    /* Image smaller than screen? */
  155.     LONG        TinyX, TinyY;    /* Image offsets for tiny bitmap. */
  156.  
  157.     struct IntuiMessage *Message;
  158.  
  159.     ULONG        Class;
  160.     UWORD        Code;
  161.  
  162.     WORD        i;        /* Loop counters. */
  163.  
  164.     volatile UBYTE *RightMouse = (UBYTE *) 0xDFF016;
  165.  
  166.     char        RealName[108];
  167.  
  168.     GRName(FileName, RealName);
  169.  
  170.     /* Is it the last picture? */
  171.  
  172.     if (LastOne)
  173.     MenuItem[11].Flags &= ~ITEMENABLED;
  174.     else
  175.     MenuItem[11].Flags |= ITEMENABLED;
  176.  
  177.     /* Try to load the header. */
  178.  
  179.     if ((ViewModes = LoadHead(FileName, &InfoHeader)) == -1)
  180.     return (ERR_NOIFF);
  181.  
  182.     /* Are there any colors out there? */
  183.  
  184.     if (!(ColorNumber = LoadCMAP(FileName, Colors, 32, &InfoHeader)))
  185.     return (ERR_NOCOLMAP);
  186.  
  187.     /* Take care of the size of the ViewPort. */
  188.  
  189.     Width = InfoHeader.pageWidth;
  190.     Height = InfoHeader.pageHeight;
  191.  
  192.     /* Forced scrolling? */
  193.  
  194.     if (ForceScroll)
  195.     ViewModes &= ~(HIRES | LACE);
  196.  
  197.     /* Forced interlaced display mode? */
  198.  
  199.     if (ForceLace)
  200.     ViewModes |= LACE;
  201.  
  202.     /* Take care of exotic screen sizes. */
  203.  
  204.     if (InfoHeader.h > Height)
  205.     Height = InfoHeader.h;
  206.  
  207.     if (InfoHeader.w > Width)
  208.     Width = InfoHeader.w;
  209.  
  210.     /* Hires or lores? */
  211.  
  212.     if (ViewModes & HIRES) {
  213.     Width = 640;
  214.     JumpX = 2;
  215.     } else
  216.     Width = 320;
  217.  
  218.     /*
  219.      * Interlaced or not? This may get funny since it is possible to scroll
  220.      * the image in steps of one pixel. In doing so one copper list (either
  221.      * shortframe or longframe) is ignored and only half of the image is
  222.      * displayed correctly. To avoid this the scroll jump is set to two
  223.      * pixels.
  224.      */
  225.  
  226.     if (ViewModes & LACE)
  227.     JumpY = 2;
  228.  
  229.     if (Height > GfxBase->NormalDisplayRows * JumpY)
  230.     Height = GfxBase->NormalDisplayRows * JumpY;
  231.  
  232.     /* Adjust the information. */
  233.  
  234.     NewScreen.Width = Width;
  235.     NewScreen.Height = Height;
  236.     NewScreen.Depth = InfoHeader.nPlanes;
  237.     NewScreen.ViewModes = ViewModes;
  238.  
  239.     /* And don't forget the window. */
  240.  
  241.     NewWindow.Width = Width;
  242.     NewWindow.Height = Height;
  243.  
  244.     /* Anything wrong with the picture? */
  245.  
  246.     if (InfoHeader.w < InfoHeader.pageWidth || InfoHeader.h < InfoHeader.pageHeight) {
  247.     if (!ITBMap())
  248.         return (ERR_NOMEM);
  249.  
  250.     IsTiny = TRUE;
  251.     } else {
  252.  
  253.     /* Initialize the bitmap for future use. */
  254.  
  255.     InitBitMap(&ScreenMap, InfoHeader.nPlanes, InfoHeader.w, InfoHeader.h);
  256.  
  257.     /* Try to steal some memory for the bitplanes. */
  258.  
  259.     for (i = 0; i < InfoHeader.nPlanes; i++) {
  260.         if (!(ScreenMap.Planes[i] = (PLANEPTR) AllocRaster(InfoHeader.w, InfoHeader.h)))
  261.         return (ERR_NOMEM);
  262.  
  263.         IsTiny = FALSE;
  264.     }
  265.     }
  266.  
  267.     /* Open the screen. */
  268.  
  269.     if (!(Screen = (struct Screen *) OpenScreen(&NewScreen)))
  270.     return (ERR_NOMEM);
  271.  
  272.     /* Hide the title bar and prepare the window. */
  273.  
  274.     ShowTitle(Screen, FALSE);
  275.  
  276.     NewWindow.Screen = Screen;
  277.  
  278.     /* Try to open the window. */
  279.  
  280.     if (!(Window = (struct Window *) OpenWindow(&NewWindow)))
  281.     return (ERR_NOMEM);
  282.  
  283.     SetSnooze(Window);
  284.  
  285.     SetWindowTitles(Window, (CPTR) - 1, (CPTR) RealName);
  286.  
  287. #ifdef    FANCYMENU
  288.  
  289.     /* Set up the alternate colour palette. */
  290.  
  291.     for (i = 0; i < 32; i++) {
  292.     PrefColors[i] = Colors[i];
  293.  
  294.     if (i >= (1 << NewScreen.Depth))
  295.         PrefColors[i] = Colors[i] = GetRGB4(Screen->ViewPort.ColorMap, i);
  296.     }
  297.  
  298.     PrefColors[0] = StandardPrefs.color0;
  299.     PrefColors[1] = StandardPrefs.color1;
  300.     PrefColors[2] = StandardPrefs.color2;
  301.     PrefColors[3] = StandardPrefs.color3;
  302.  
  303. #endif                /* FANCYMENU */
  304.  
  305.     /* Load the colors. */
  306.  
  307.     LoadRGB4(&Screen->ViewPort, Colors, ColorNumber);
  308.  
  309.     /* Just in case we will have to restore it. */
  310.  
  311.     StartOffsetX = Screen->ViewPort.RasInfo->RxOffset;
  312.     StartOffsetY = Screen->ViewPort.RasInfo->RyOffset;
  313.  
  314.     /*
  315.      * Play it safe --- keep the maximum scroll offset in reasonable
  316.      * dimensions.
  317.      */
  318.  
  319.     if ((MaxOffsetX = InfoHeader.w - Width) < 0)
  320.     MaxOffsetX = 0;
  321.  
  322.     if ((MaxOffsetY = InfoHeader.h - Height) < 0)
  323.     MaxOffsetY = 0;
  324.  
  325.     /* Absolute maximum limit. */
  326.  
  327.     MaxOffsetX += StartOffsetX;
  328.     MaxOffsetY += StartOffsetY;
  329.  
  330.     /* "Here comes the sun..." */
  331.  
  332.     if (IsTiny) {
  333.     if (!LoadRast(FileName, TinyBitMap.Planes, &InfoHeader))
  334.         return (ERR_DOS);
  335.     } else {
  336.     if (!LoadRast(FileName, ScreenMap.Planes, &InfoHeader))
  337.         return (ERR_DOS);
  338.     }
  339.  
  340.     /* Do we allow color cycling? */
  341.  
  342.     if (LoadCycleRange(FileName, CycleRange, 6))
  343.     InitCycle(&Screen->ViewPort, Colors, ColorNumber, CycleRange, 6);
  344.  
  345.     /* Install the menu and the pointer. */
  346.  
  347.     SetMenuStrip(Window, &Menu);
  348.     SetPoint(Window);
  349.  
  350.     /* And - if necessary - print the tiny image. */
  351.  
  352.     if (IsTiny) {
  353.     if (InfoHeader.x + InfoHeader.w <= Screen->Width)
  354.         TinyX = InfoHeader.x;
  355.     else
  356.         TinyX = (NewScreen.Width - InfoHeader.w) >> 1;
  357.  
  358.     if (InfoHeader.y + InfoHeader.h <= Screen->Height)
  359.         TinyY = InfoHeader.y;
  360.     else
  361.         TinyY = (NewScreen.Height - InfoHeader.h) >> 1;
  362.  
  363.     BltBitMap(&TinyBitMap, 0, 0, Screen->RastPort.BitMap, TinyX, TinyY, InfoHeader.w, InfoHeader.h, 0xC0, 0xFF, NULL);
  364.     }
  365.     /* Paint the screen black (for the effect). */
  366.  
  367.     if (!(ViewModes & HAM))
  368.     LoadRGB4(&Screen->ViewPort, BlackIsBlack, ColorNumber);
  369.  
  370.     /* Bring the screen to the front. */
  371.  
  372.     ScreenToFront(Screen);
  373.     ActivateWindow(Window);
  374.  
  375.     FreeSprite(0);
  376.  
  377.     /* Fade the colors in. */
  378.  
  379.     if (!(ViewModes & HAM))
  380.     FadeTo(&Screen->ViewPort, NULL, Colors, ColorNumber, 0, 0);
  381.  
  382.     /* Allow the menu to be selected. */
  383.  
  384.     Window->Flags &= ~RMBTRAP;
  385.  
  386.     /* If we are to cycle... */
  387.  
  388.     if (CycleOnStartup)
  389.     ToggleCycle();
  390.  
  391.     FOREVER
  392.     {
  393.  
  394.     /* Let's be nice and wait for reactions. */
  395.  
  396.     WaitPort(Window->UserPort);
  397.  
  398.     /* Message the userport. */
  399.  
  400.     if (Message = (struct IntuiMessage *) GetMsg(Window->UserPort)) {
  401.         Class = Message->Class;
  402.         Code = Message->Code;
  403.  
  404.         /*
  405.          * If the user presses the menu button the menu appears. There is
  406.          * nothing wrong with this, but it might be possible that the
  407.          * user does not see the menu because of the raster offset. So we
  408.          * reposition the ViewPort before Intuition renders the menu bar.
  409.          * To keep the menu visible we adjust the colors if the right
  410.          * mouse button is pressed. This is done because of the fact that
  411.          * the keyboard shortcuts generate the same MENUVERIFY event. If
  412.          * there is anyone who doesn't like it this way he can try to
  413.          * test the keyboard matrix by tickling the hardware. I have
  414.          * chosen the easier way.
  415.          */
  416.  
  417.         if (Class == MENUVERIFY && !(*RightMouse & 4)) {
  418.         if (WasCycling = IsCycle())
  419.             ToggleCycle();
  420.  
  421. #ifdef    FANCYMENU
  422.  
  423.         LoadRGB4(&Screen->ViewPort, PrefColors, 32);
  424.         ChangedColors = TRUE;
  425.  
  426. #endif                /* FANCYMENU */
  427.  
  428.         /* Reset the offsets. */
  429.  
  430.         Screen->ViewPort.RasInfo->RxOffset = StartOffsetX;
  431.         Screen->ViewPort.RasInfo->RyOffset = StartOffsetY;
  432.  
  433.         /* Remake the copper list. */
  434.  
  435.         MakeScreen(Screen);
  436.         RethinkDisplay();
  437.         }
  438.         ReplyMsg(Message);
  439.     }
  440.     /*
  441.      * If the user presses the select button we'll assume that he wants
  442.      * to scroll around in the picture.
  443.      */
  444.  
  445.     if (Class == MOUSEBUTTONS && Code == SELECTDOWN) {
  446.         FreeSprite(0);
  447.  
  448.         if (ChangedColors) {
  449.         LoadRGB4(&Screen->ViewPort, Colors, ColorNumber);
  450.         ChangedColors = FALSE;
  451.  
  452.         if (WasCycling)
  453.             ToggleCycle();
  454.  
  455.         WasCycling = FALSE;
  456.         }
  457.         WeAreScrolling = TRUE;
  458.         IsMouse = TRUE;
  459.     }
  460.     /*
  461.      * User pressed the cursor keys and wants to scroll around in the
  462.      * picture.
  463.      */
  464.  
  465.     if (Class == RAWKEY && (Code & ~IECODE_UP_PREFIX) >= CURSORUP && (Code & ~IECODE_UP_PREFIX) <= CURSORLEFT) {
  466.         FreeSprite(0);
  467.  
  468.         WeAreScrolling = TRUE;
  469.         IsMouse = FALSE;
  470.     }
  471.     /*
  472.      * User didn't like the menu shortcut and pressed the Tab key (is he
  473.      * a DPaint fanatic?).
  474.      */
  475.  
  476.     if (Class == RAWKEY && Code == 0x42) {
  477.         FreeSprite(0);
  478.  
  479.         ToggleCycle();
  480.     }
  481.     /* The user picked a menu item. */
  482.  
  483.     if (Class == MENUPICK) {
  484.         if (ChangedColors) {
  485.         LoadRGB4(&Screen->ViewPort, Colors, ColorNumber);
  486.  
  487.         if (WasCycling)
  488.             ToggleCycle();
  489.  
  490.         ChangedColors = FALSE;
  491.         WasCycling = FALSE;
  492.         }
  493.         MenuNum = Code;
  494.  
  495.         /* Until the last event is traced. */
  496.  
  497.         while (MenuNum != MENUNULL) {
  498.         if (MENUNUM(MenuNum) == 0) {
  499.             switch (ITEMNUM(MenuNum)) {
  500.  
  501.             /* About... */
  502.  
  503.             case 0:
  504.             if (WasCycling = IsCycle())
  505.                 ToggleCycle();
  506.  
  507. #ifdef    FANCYMENU
  508.  
  509.             LoadRGB4(&Screen->ViewPort, PrefColors, 32);
  510.  
  511. #endif                /* FANCYMENU */
  512.  
  513.             Screen->ViewPort.RasInfo->RxOffset = StartOffsetX;
  514.             Screen->ViewPort.RasInfo->RyOffset = StartOffsetY;
  515.  
  516.             /* Remake the copper list. */
  517.  
  518.             MakeScreen(Screen);
  519.             RethinkDisplay();
  520.  
  521.             InitRequester(&Req);
  522.  
  523.             Req.Width = 300;
  524.             Req.Height = 175;
  525.  
  526.             Req.LeftEdge = (Window->Width - Req.Width) / 2;
  527.             Req.TopEdge = (Window->Height - Req.Height) / 2;
  528.  
  529.             Req.BackFill = 1;
  530.  
  531.             Req.Flags = NOISYREQ | SIMPLEREQ;
  532.             Req.ReqGadget = &ReqGad;
  533.             Req.ReqBorder = &ReqBrd[2];
  534.             Req.ReqText = &ReqIntTxt[1];
  535.  
  536.             if (Request(&Req, Window)) {
  537.                 FOREVER
  538.                 {
  539.                 WaitPort(Window->UserPort);
  540.  
  541.                 while (Message = (struct IntuiMessage *) GetMsg(Window->UserPort)) {
  542.                     Class = Message->Class;
  543.  
  544.                     ReplyMsg(Message);
  545.  
  546.                     if (Class == GADGETUP) {
  547.                     EndRequest(&Req, Window);
  548.                     goto EndReq;
  549.                     }
  550.                 }
  551.                 }
  552.             }
  553.             EndReq:
  554.             SetPoint(Window);
  555.  
  556.             LoadRGB4(&Screen->ViewPort, Colors, ColorNumber);
  557.  
  558.             if (WasCycling)
  559.                 ToggleCycle();
  560.  
  561.             FreeSprite(0);
  562.             break;
  563.  
  564.             /* Toggle the presence of the screen title. */
  565.  
  566.             case 2:
  567.             FreeSprite(0);
  568.  
  569.             if (Screen->Flags & SHOWTITLE)
  570.                 ShowTitle(Screen, FALSE);
  571.             else
  572.                 ShowTitle(Screen, TRUE);
  573.  
  574.             break;
  575.  
  576.             /* Toggle cycling. */
  577.  
  578.             case 3:
  579.             FreeSprite(0);
  580.  
  581.             ToggleCycle();
  582.             break;
  583.  
  584.             /* Print screen */
  585.  
  586.             case 5:
  587.             if (IsCycle())
  588.                 ToggleCycle();
  589.  
  590.             WasCycling = FALSE;
  591.  
  592.             /* Remake the copper list. */
  593.  
  594.             MakeScreen(Screen);
  595.             RethinkDisplay();
  596.  
  597.             PrintPix();
  598.  
  599.             break;
  600.  
  601.             /* Modify colors and start the presses */
  602.  
  603.             case 7:
  604.             if (IsCycle())
  605.                 ToggleCycle();
  606.  
  607.             WasCycling = FALSE;
  608.  
  609.             DoCWind(Screen, 10, 10, 1, TRUE);
  610.             break;
  611.  
  612.             /* Iconify */
  613.  
  614.             case 9:
  615.             if (IsCycle())
  616.                 ToggleCycle();
  617.             WasCycling = FALSE;
  618.  
  619.             ScreenToBack(Screen);
  620.  
  621.             CloseDisp();
  622.  
  623.             Iconize();
  624.  
  625.             return (0);
  626.  
  627.             /* Next Picture */
  628.  
  629.             case 11:
  630.             if (IsCycle())
  631.                 ToggleCycle();
  632.  
  633.             WasCycling = FALSE;
  634.  
  635.             if (!(ViewModes & HAM))
  636.                 FadeTo(&Screen->ViewPort, Colors, NULL, ColorNumber, 0, 0);
  637.  
  638.             ScreenToBack(Screen);
  639.  
  640.             CloseDisp();
  641.  
  642.             return (0);
  643.  
  644.             /* Quit SeePix. */
  645.  
  646.             case 12:
  647.             SPQuit();
  648.  
  649.             }
  650.         }
  651.         /* See if there is another menu item around. */
  652.  
  653.         Item = (struct MenuItem *) ItemAddress(&Menu, MenuNum);
  654.  
  655.         MenuNum = Item->NextSelect;
  656.         }
  657.     }
  658.     /* No chance to scroll anywhere, so we'll block it. */
  659.  
  660.     if (MaxOffsetX == StartOffsetX && MaxOffsetY == StartOffsetY)
  661.         WeAreScrolling = FALSE;
  662.  
  663.     /*
  664.      * This loop will run until the select button or the cursor key is
  665.      * released.
  666.      */
  667.  
  668.     while (WeAreScrolling) {
  669.         if (Message = (struct IntuiMessage *) GetMsg(Window->UserPort)) {
  670.         Class = Message->Class;
  671.         Code = Message->Code;
  672.  
  673.         ReplyMsg(Message);
  674.         }
  675.         /* User doesn't want to scroll anymore? */
  676.  
  677.         if (Code & IECODE_UP_PREFIX) {
  678.         FreeSprite(0);
  679.         WeAreScrolling = FALSE;
  680.         }
  681.         /* Nothing happened. */
  682.  
  683.         RemakeTheView = FALSE;
  684.  
  685.         /* Left border, scroll left. */
  686.  
  687.         if (((Window->MouseX == 0 && IsMouse) || (Code == CURSORLEFT && !IsMouse)) && (Screen->ViewPort.RasInfo->RxOffset - JumpX >= StartOffsetX)) {
  688.         Screen->ViewPort.RasInfo->RxOffset -= JumpX;
  689.         RemakeTheView = TRUE;
  690.         }
  691.         /* Top border, scroll up. */
  692.  
  693.         if (((Window->MouseY == 0 && IsMouse) || (Code == CURSORUP && !IsMouse)) && (Screen->ViewPort.RasInfo->RyOffset - JumpY >= StartOffsetY)) {
  694.         Screen->ViewPort.RasInfo->RyOffset -= JumpY;
  695.         RemakeTheView = TRUE;
  696.         }
  697.         /* Right border, scroll right. */
  698.  
  699.         if (((Window->MouseX == Window->Width - 1 && IsMouse) || (Code == CURSORRIGHT && !IsMouse)) && (Screen->ViewPort.RasInfo->RxOffset + JumpX <= MaxOffsetX)) {
  700.         Screen->ViewPort.RasInfo->RxOffset += JumpX;
  701.         RemakeTheView = TRUE;
  702.         }
  703.         /* Bottom border, scroll down. */
  704.  
  705.         if (((Window->MouseY == Window->Height - 1 && IsMouse) || (Code == CURSORDOWN && !IsMouse)) && (Screen->ViewPort.RasInfo->RyOffset + JumpY <= MaxOffsetY)) {
  706.         Screen->ViewPort.RasInfo->RyOffset += JumpY;
  707.         RemakeTheView = TRUE;
  708.         }
  709.         /* Are we to scroll the ViewPort? */
  710.  
  711.         if (RemakeTheView) {
  712.         MakeScreen(Screen);
  713.         RethinkDisplay();
  714.         }
  715.     }
  716.     }
  717. }
  718.